<template class="ref">
  <h1>ref、Ref使用</h1>

  <div class="box">
    <p>使用ref定义变量</p>
    <input type="text" v-model="numa" />
    <button @click="count(true)">+</button>
    <button @click="count(false)">-</button>
  </div>
  <div class="box">
    <p>使用Ref定义变量</p>
    <h3>numb:{{ numb }}</h3>
    <button @click="numeration(true)">+</button>
    <br />
    <button @click="numeration(false)">-</button>
  </div>
  <div class="box">
    <p>isRef判断是不是ref对象</p>
    <h3>let notRef: string = "不是ref对象";</h3>
    <h3>
      const isRRef = (value: any): boolean => { alert(isRef(value)); return
      isRef(value); };
    </h3>
    <br />
    <button @click="isRRef(notRef)">判断是不是ref对象</button>
  </div>
  <div class="box">
    <p>使用shallowRef定义变量</p>
    <h3>msg:{{ msg }}</h3>
    <p>
      此方式无法改变响应式msg的值 需配合triggerRef(ref)强制刷新dom
      <button @click="changeMsg()">改变msg</button>
    </p>
    <button @click="changeMsg1()">改变msg</button>
  </div>
  <div class="box">
    <p>customRef</p>
    <h3>customRefMsg:{{ customRefMsg }}</h3>
    <p>
      <button @click="changeCustomRefMsg()">改变customRefMsg</button>
    </p>
  </div>
</template>

<script setup lang="ts">
import {
  ref,
  Ref,
  isRef,
  shallowRef,
  triggerRef,
  customRef,
  onMounted,
} from "vue";
// isRef 判断是不是ref对象
let numa = ref(123);
let numb: Ref<number> = ref(123);
let notRef: string = "不是ref对象";

const isRRef = (value: any): boolean => {
  alert(isRef(value));
  return isRef(value);
};
const count = (b: boolean) => {
  if (b) numa.value++;
  else numa.value--;
};
const numeration = (b: boolean) => {
  if (b) numb.value++;
  else numb.value--;
};

// shallowRef
// 创建一个跟踪自身.value变化的ref，但不会使其值也变成响应式的

// triggerRef
// 强制更新dom
type Obj = {
  name: string;
};

let msg: Ref<Obj> = shallowRef({
  name: "msgggggg",
});

const changeMsg = () => {
  msg.value.name =
    "此方式无法改变响应式msg的值 需配合triggerRef(ref)强制刷新dom";
  triggerRef(msg);
  console.log(msg);
};
// 需直接改变.value 后面的值
const changeMsg1 = () => {
  msg.value = { name: "正确的写法，改变了msg" };
  console.log(msg);
};
// customRef 用于自定义ref
// 返回一个ref对象,可以显式地控制依赖追踪和触发响应
function MyRef<T>(value: T) {
  return customRef((trank, trigger) => {
    // customer 需要提供一个对象 作为返回值
    // 该对象需要包含 get 和 set 方法。
    return {
      get() {
        console.log("get", value);
        // track 方法放在 get 中，用于提示这个数据是需要追踪变化的
        trank();
        return value;
      },
      // set 传入一个值作为新值，通常用于取代 value
      set(newValue: T) {
        console.log("set newValue=", newValue);
        value = newValue;
        // 记得触发事件 trigger,告诉vue触发页面更新
        trigger();
      },
    };
  });
}
// 应用上面的自定义 customRef ，使用方案和之前的 ref 是类似的。
let customRefMsg = MyRef<string>("小陈");

const changeCustomRefMsg = () => {
  customRefMsg.value = "大陈";
};

onMounted(() => {
  console.log("notRef", isRef(notRef)); // => false
  console.log("numa", isRef(numa)); // => true
  console.log("numb", isRef(numb)); // => true
});
</script>

<style lang="less" scoped>
.box {
  padding: 10px;
  margin: 10px;
}
</style>
